<?Php

    /**
     * Control-компонент модели MVC
     *
     * public function process($configFile);   // собственно, контроллер
     * private function loadConfigs($file);    // читаем конфиги
     * private function authorise();           // авторизация
     * private function parseUrl();            // парсер url
     * private function userRequest();         // обработчик запросов
     */


    // Controller-компонент модели MVC
    class Controller implements SplSubject{


        private $storage;
        private $error, $result, $loggedin, $privelegies;
        private $section, $file;
        private $htmlstatecode;


        // стандартная обёртка для подключения плагинов
        // http://ru.wikipedia.org/wiki/Наблюдатель_(шаблон_проектирования)#PHP5_.28SPL.29
        function __construct()                  {$this->storage = new SplObjectStorage();}
        function attach(SplObserver $observer)  {$this->storage->attach($observer);}
        function detach(SplObserver $observer)  {$this->storage->detach($observer);}
        function notify()                       {foreach($this->storage as $obj)$obj->update($this, $info);}
        // заглушка для передачи инфы в плагины
        function notifyPlugins($info)           {$this->info = $info; $this->notify();}




        /**
         * сам контроллер. Оформлен как фасад
         * http://ru.wikipedia.org/wiki/Фасад_(шаблон_проектирования)
         */
        public function process($configFile){   //                                  == controller
            
            $this -> loadConfigs($configFile);  // чтение конфигов
            
            $this -> attachPlugins();           // подключаем плагины
            
            $this -> authorise();               // авторизация
            $this -> notifyPlugins('authorise');// подключаем плагины по этапу "авторизация"
            
            $this -> parseUrl();                // обработали адрес страницы
            $this -> notifyPlugins('parseUrl'); // подключаем плагины по этапу "парсинг URL"
            
            $this -> userRequest();             // обработали запросы по POST/GET   == model
            $this -> notifyPlugins('usRequest');// подключаем плагины по этапу "обработка запроса"
            
            if ($this->error)                   // возвращаем ответ пользователю    == view
                    View::displayError( model::getData(), $this->error,  $this->htmlstatecode );
            else
                    View::displayPage(  model::getData(), model::getPage($this->section), $this->result);

        } // processData





        /**
         * читаем конфиги
         */
        private function loadConfigs($file){
            
            require_once($file);
            
            // задаём глобальные настройки
            foreach($cnf['inis'] as $k => $v) ini_set($k,$v);
            foreach($cnf['defs'] as $k => $v) defined($k) OR define($k,$v);
            
            // подключаем базу данных
            if (!class_exists('PDO'))die ('Пожалуйста, установите поддержку mysql через PDO!');
            $this -> pdo = new PDO( $cnf['dbtype'] . ':host=' . $cnf['dbhost'] . ';dbname=' . $cnf['dbname'],
                                    $cnf['dbuser'], $cnf['dbpass'] );
            $q = $this -> pdo -> query( 'SET NAMES utf8' ); // мало ли какие извращения встречаются!
            
            // подключаем обёртки функций для работы с БД
            $this -> db = new database( $this -> pdo );
            
            // создаём синглетон для хранения настроек
            // http://ru.wikipedia.org/wiki/Одиночка_(шаблон_проектирования)
            $this -> pref = preferences::getInstance();
            $this -> pref -> setProperty( 'pdo', $this -> pdo );
            $this -> pref -> setProperty( 'db', $this -> db );
            
            // подключаем мемкеш, если есть и разрешён в config.inc
            if ((class_exists('Memcached') OR class_exists('Memcache')) AND ALLOW_MEMCACHED){
                $this -> memcache = new mc();
                $this -> pref -> setProperty( 'memcache', $this -> memcache );
            }
            
            // дефолтное сообщение об ошибке
            $this -> htmlstatecode = $cnf['defaultHtmlStateCode'];
            $this -> error = $cnf['defaultErrorCode'];
            
        } // loadConfigs



        /**
         * подключаем плагины
         */
        private function attachPlugins(){
            
            // задаём настройки для работы плагинов
            $e = $this -> db -> sel (DB_MODEL_DEFINES, '*');
            foreach($e as $v){ defined($v['define_title']) OR define($v['define_title'],$v['define_value']); }
            $e = $this -> db -> sel (DB_MODEL_PLUGINS, '*', "`enabled`='1'");
            foreach($e as $v)$plugIns[$v['id']] = $v;
            $this -> pref -> setProperty( 'plugInsInfo', $plugIns );
            
            // подключаем плагины-наблюдатели к контроллеру (class $v['title'] extends ControllerObserver)
            // http://ru.wikipedia.org/wiki/Наблюдатель_(шаблон_проектирования)#PHP5_.28SPL.29
            foreach($e as $v){
                $filepath = $v['folder'] . '/';
                $filepath = str_replace('/', DIRECTORY_SEPARATOR, $filepath);
                $filepath = str_replace('\\', DIRECTORY_SEPARATOR, $filepath);
                if (file_exists($filepath . 'functions.php'))require_once ($filepath . 'functions.php');
                if (file_exists($filepath . '_control.php')){
                    require_once ($filepath . '_control.php');
                    new $v['title']($this);
                }
                if ($v['type']=='plugin')$usedPlugins[]=$v['id'];
            }
            define ('USED_PLUGINS',$usedPlugins);
        }



        /**
         * авторизация
         */
        private function authorise(){ // реально лежит во внешней библиотеке functions.php, здесь только фасад
            
            $auth = new authorisation();
            $auth -> checkAuth();
            $this -> loginData = $this -> pref -> getProperty('loginData');
            
        } // authorise





        /**
         * парсер url
         */
        private function parseUrl(){ // реально лежит во внешней библиотеке functions.php, здесь только фасад
            
            $urlParser = new urlParser($_SERVER['REQUEST_URI'], $_SERVER['PHP_SELF']);
            $urlParser -> parseUrl();
            
            $this -> section = $urlParser -> section;
            $this -> error = $urlParser -> error;
            $this -> htmlstatecode = $urlParser -> htmlstatecode;
            
        } // parseUrl





        /**
         * обработчик запросов, вызов model-компоненты модели MVC
         */
        private function userRequest() {
            if (sizeof($_REQUEST)==0)return null;           // нет реквестов
            else 
            {                                               // есть реквесты
                $out=model::proceedData(ekran($_REQUEST));
                
                if ($out['error'])
                    $this->error=$out['error'];
                $this->result=$out['result'];
            }
        } // userRequest



    } // class Controller







    // обвязка для подключения плагинов к контроллеру
    // http://ru.wikipedia.org/wiki/Наблюдатель_(шаблон_проектирования)#PHP5_.28SPL.29
    abstract class ControllerObserver implements SplObserver
    {
        private $observable;
        function __construct(Controller $observable)
        {
            $this->observable = $observable;
            $observable->attach($this);
        }
        function update(SplSubject $subject)
        {
            if($subject === $this->observable)$this->doUpdate($subject);
        }
        abstract function doUpdate(Controller $observable);
    } // abstract class ControllerObserver implements SplObserver
    
    
    

?>